using System;
using System.Diagnostics;
using System.IO;
using System.Xml.Serialization;
using Microsoft.SharePoint;
using System.Collections.Generic;
using DE.Sdc.SharePoint.SPContentStructure.Common;

namespace DE.Sdc.SharePoint.SPContentStructure.Import
{
    [Serializable]
    [XmlType(AnonymousType = true, Namespace = DeploymentConstants.Namespace)]
    [XmlRoot(Namespace = DeploymentConstants.Namespace, IsNullable = false)]
    public class Folder : BaseItem<Folder>, IImportDefinition<SPFolder, SPFolder>
    {
        private string _path;

        public Folder()
        {
            Folders = new HierarchicalList<Folder, Folder>(this);
            Items = new HierarchicalList<Folder, Item>(this);
        }

        /// <remarks/>
        [XmlAttribute]
        public bool Approve { get; set; }

        /// <remarks/>
        [XmlAttribute]
        public bool FindItemsRecursive { get; set; }

        /// <remarks/>
        [XmlElement]
        public BulkImport BulkImport { get; set; }

        /// <remarks/>
        [XmlArrayItem("Folder", typeof(Folder))]
        public HierarchicalList<Folder, Folder> Folders { get; set; }

        [XmlIgnore]
        public bool FoldersSpecified
        {
            get
            {
                return Folders != null && Folders.Count > 0;
            }
        }

        /// <remarks/>
        [XmlArrayItem("Item", typeof(Item))]
        public HierarchicalList<Folder, Item> Items { get; set; }

        [XmlIgnore]
        public bool ItemsSpecified
        {
            get
            {
                return Items != null && Items.Count > 0;
            }
        }

        [XmlAttribute]
        public string Path
        {
            get
            {
                if (!string.IsNullOrEmpty(_path) || GetType() == typeof(SPContentStructureImport))
                    return _path;

                if (Parent != null)
                    return Parent.Path + @"\" + Title;

                return null;
                // throw new ArgumentNullException("No path specified for '" + Title + "'");
            }
            set
            {
                _path = value;
            }
        }

        //[XmlElement(typeof(PowershellNodes))]
        //public PowershellNodes PowerShellNodes { get; set; }


        [XmlIgnore]
        public SPFolder UpdatedSPObject { get; internal set; }

        protected override bool IsNewVersion(object sharePointObject)
        {
            if (sharePointObject == null || Version == 0)
                return true;
            SPFolder folder = (SPFolder) sharePointObject;
            Trace.WriteLine("Check version number for object '" + folder.Url + "'",
                            "ContentStructureImporter:ImportFolder");

            if (folder.Properties.ContainsKey(DeploymentConstants.ContentStructureVersion))
            {
                int currentVersion = int.Parse((string) folder.Properties[DeploymentConstants.ContentStructureVersion]);
                Trace.WriteLine(
                    "Current version is " + currentVersion + ", new version is " + Version + " for object '" +
                    folder.Url + "'", "ContentStructureImporter:ImportFolder");

                return Version > currentVersion;
            }

            return true;
        }

        protected override void SetNewVersion(object sharePointObject)
        {
            if (sharePointObject == null || Version == 0)
                return;

            SPFolder web = (SPFolder) sharePointObject;
            if (web.Properties.ContainsKey(DeploymentConstants.ContentStructureVersion))
                web.Properties[DeploymentConstants.ContentStructureVersion] = Version.ToString();
            else
                web.Properties.Add(DeploymentConstants.ContentStructureVersion, Version.ToString());
        }

        /// <summary>
        /// Creates a folder in a given parent folder
        /// </summary>
        /// <param name="parentFolder">The parent folder where to create the folder</param>
        /// <returns></returns>
        private SPFolder CreateFolder(SPFolder parentFolder)
        {
            Trace.WriteLine("Try to create folder '" + Title + "' with url '" + AbsoluteUrl + "'.",
                            "ContentStructureImporter:CreateFolder");
            string folderUrl = Url;

            if (string.IsNullOrEmpty(folderUrl))
                folderUrl = parentFolder.ServerRelativeUrl.TrimEnd('/');

            SPListItem folderItem = parentFolder.ParentWeb.Lists[parentFolder.ParentListId].Folders.Add(folderUrl,
                                                                                                        SPFileSystemObjectType.Folder,
                                                                                                        Title);
            folderItem.Update();

            Trace.WriteLine("Folder '" + Title + "' with url '" + AbsoluteUrl + "' created.",
                            "ContentStructureImporter:CreateFolder");

            return folderItem.Folder;
        }

        /// <summary>
        /// Imports a folder into a given folder including subfolders, items and files
        /// </summary>
        /// <param name="parentFolder">The parent folder where to insert the bulk import</param>
        private void ImportBulk(SPFolder parentFolder)
        {
            Trace.WriteLine("Try to import bulk into folder '" + Title + "' with url '" + AbsoluteUrl + "'.", "ContentStructureImporter:ImportFolder");

            string importPath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), File.GetFeatureRootedPath(BulkImport.Path));
            ActionType importAction = BulkImport.Action;

            if (string.IsNullOrEmpty(importPath))
                throw new ArgumentNullException("Attribute 'Path' for Element 'Import' in Folder '" + parentFolder.Name +
                                                "' is NotSupportedException specified.");

            if (!Directory.Exists(importPath) && BulkImport.IgnoreIfPathNotExists)
                return;

            string[] subFolderPathes = Directory.GetDirectories(importPath);
            string[] filePathes = Directory.GetFiles(importPath);

            foreach (string subFolderPath in subFolderPathes)
            {
                Folder subFolderDefinition = new Folder
                                                 {
                                                     Action = importAction,
                                                     Title = System.IO.Path.GetFileName(subFolderPath),
                                                     BulkImport = new BulkImport { Path = subFolderPath, Action = importAction },
                                                     Path = subFolderPath,
                                                     Parent = this
                                                 };
                SPFolder subFolder = null;
                try
                {
                    subFolder = parentFolder.SubFolders[subFolderDefinition.Title];
                }
                catch (ArgumentNullException)
                {
                }
                catch (ArgumentException)
                {
                }

                subFolderDefinition.ImportDefinition(subFolder, parentFolder);
            }

            foreach (string filePath in filePathes)
            {
                Item itemDefinition = new Item
                                          {  
                                              Action = importAction,
                                              Title = System.IO.Path.GetFileName(filePath),
                                              Parent = this,
                                              File = filePath.ToLowerInvariant().EndsWith(".aspx") ?
                                                new Page { Path = filePath, FileAction = FileActionType.Approve, Action = importAction } :
                                                new File { Path = filePath, FileAction = FileActionType.Approve, Action = importAction }
                                          };

                SPFile file = null;
                try
                {
                    file = parentFolder.Files[itemDefinition.Title];
                }
                catch (FileNotFoundException) { }
                catch (ArgumentNullException) { }
                catch (ArgumentException) { }

                itemDefinition.ImportDefinition(file != null ? file.Item : null, parentFolder);
            }

            Trace.WriteLine("Bulk import into folder '" + Title + "' with url '" + AbsoluteUrl + "' imported.", "ContentStructureImporter:ImportFolder");
        }

        /// <summary>
        /// Adds, Replaces, Deletes, Modifies or Moves a folder in a given folder
        /// </summary>
        /// <param name="folder">A folder based on the folderDefinition or null</param>
        /// <param name="parentFolder">The parent where to import the folder</param>
        public void ImportDefinition(SPFolder folder, SPFolder parentFolder)
        {
            Trace.WriteLine("Try to import folder '" + Title + "' with url '" + AbsoluteUrl + "'.", "ContentStructureImporter:ImportFolder");

            if (parentFolder != null)
            {
                if (folder == null || !folder.Exists)
                {
                    if (Action == ActionType.AddOrUpdate || Action == ActionType.Replace)
                        folder = CreateFolder(parentFolder);
                    else
                        return;
                }
                else if (Action == ActionType.Replace && IsNewVersion(folder))
                {
                    folder.Delete();
                    folder = CreateFolder(parentFolder);
                }
                else if (Action == ActionType.Delete)
                {
                    folder.Delete();
                    return;
                }
            }

            SetNewVersion(folder);

            DeploymentContext.Current.Folder = folder;
            DeploymentContext.Current.FolderDefinition = this;
            DeploymentContext.Current.CurrentObjectType = DeploymentContext.DeploymentObjects.Folder;
            if (BulkImport != null)
                ImportBulk(folder);

            

            foreach (Folder subFolderDefinition in Folders)
            {
                subFolderDefinition.Title = DeploymentHelper.Resolve(subFolderDefinition.Title,
                                                                     parentFolder == null
                                                                         ? folder.ParentWeb.Locale
                                                                         : parentFolder.ParentWeb.Locale);
                subFolderDefinition.Url = DeploymentHelper.Resolve(subFolderDefinition.Url,
                                                                   parentFolder == null
                                                                       ? folder.ParentWeb.Locale
                                                                       : parentFolder.ParentWeb.Locale);
                string rootedUrl = DeploymentHelper.GetRootedUrl(subFolderDefinition.Url,
                                                folder.ServerRelativeUrl);

                SPFolder subFolder = null;

                if (!string.IsNullOrEmpty(rootedUrl))
                    subFolder = folder.ParentWeb.GetFolder(rootedUrl);
                else
                {
                    try
                    {
                        subFolder = folder.SubFolders[subFolderDefinition.Title];
                        if (!subFolder.Exists)
                            subFolder = null;
                    }
                    catch (FileNotFoundException) { }
                    catch (ArgumentNullException) { }
                    catch (ArgumentException) { }
                }

                DeploymentContext.Current.Folder = subFolder;
                DeploymentContext.Current.FolderDefinition = subFolderDefinition;
                subFolderDefinition.ImportDefinition(subFolder, folder);
            }
            DeploymentContext.Current.CurrentObjectType = DeploymentContext.DeploymentObjects.Item;
            foreach (Item itemDefinition in Items)
            {
                itemDefinition.Title = DeploymentHelper.Resolve(itemDefinition.Title,
                                                                parentFolder == null
                                                                    ? folder.ParentWeb.Locale
                                                                    : parentFolder.ParentWeb.Locale);
                itemDefinition.Url = DeploymentHelper.Resolve(itemDefinition.Url,
                                                              parentFolder == null
                                                                  ? folder.ParentWeb.Locale
                                                                  : parentFolder.ParentWeb.Locale);
                    
                string rootedUrl = DeploymentHelper.GetRootedUrl(itemDefinition.Url,
                                                folder.ServerRelativeUrl);

                SPListItem item = null;
                string[] primaryKeyFields = DeploymentContext.Current.ListDefinition.PrimaryKeyFieldsArray;
                    
                try
                {
                    item = primaryKeyFields == null ? folder.ParentWeb.GetListItem(rootedUrl ?? folder.ServerRelativeUrl + "/" + itemDefinition.Title) : GetListItems(primaryKeyFields, folder, itemDefinition)[0];
                }
                catch (FileNotFoundException) { }
                catch (ArgumentNullException) { }
                catch (ArgumentException) { }

                DeploymentContext.Current.Item = item;
                DeploymentContext.Current.ItemDefinition = itemDefinition;
                itemDefinition.ImportDefinition(item, folder);
            }
            DeploymentContext.Current.Item = null;
            DeploymentContext.Current.CurrentObjectType = DeploymentContext.DeploymentObjects.Folder;
            if (Action != ActionType.None &&
                Action <= ActionType.AddOrUpdateOrReplace)
                Properties.Modify(folder.Item);

            if (Approve)
                ApproveItem(folder.Item);

            

            folder.Update();

            

            Trace.WriteLine("Folder '" + Title + "' with url '" + AbsoluteUrl + "' imported.", "ContentStructureImporter:ImportFolder");
            UpdatedSPObject = folder;
        }
    }
}